package cn.hetra.hj212.core;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import io.netty.util.AttributeKey;

/**
 * 中华人民共和国国家环境保护标准
 * HJ 212-2017
 */
public abstract class HJ212Data {
    public static final AttributeKey<String> MN_ATTR = AttributeKey.valueOf("MN");
    public static final AttributeKey<String> ST_ATTR = AttributeKey.valueOf("ST");
    public static final AttributeKey<String> PW_ATTR = AttributeKey.valueOf("PW");
    public static final AttributeKey<Integer> VERSION_ATTR = AttributeKey.valueOf("VERSION");
    private String QN;        // 请求编码 20字符	QN=yyyyMMddHHmmssZZZ
    private String ST;        // 系统编码 5字符		ST=21
    private String CN;        // 命令编码 7字符		CN=2011
    private String PW;        // 访问密码 9字符		PW=123456
    private String MN;        // 设备标识 27字符	MN=[0-9A-F]
    private Integer PNUM;    // 总包数   9字符		PNUM=0000	[不分包则没有本字段]
    private Integer PNO;        // 包号     8字符	PNO=0000	[不分包则没有本字段]
    private int version;
    private int D;//D：是否有数据包序号；Bit：1-数据包中包含包号和总包数两部分,0-数据包中不包含包号和总包数两部分。
    private int A;//A：命令是否应答；Bit：1-应答，0-不应答。
    private CPS cps;

    public CPS getCps() {
        return cps;
    }

    public void setCps(CPS cps) {
        this.cps = cps;
    }

    public String getQN() {
        return QN;
    }

    public String getST() {
        return ST;
    }

    public String getCN() {
        return CN;
    }
    public String getPW() {
        return PW;
    }
    public String getMN() {
        return MN;
    }
    public Integer getPNUM() {
        return PNUM;
    }
    public Integer getPNO() {
        return PNO;
    }
    public int getVersion() {
        return version;
    }
    public int getD() {
        return D;
    }
    public int getA() {
        return A;
    }

    public abstract String getData();

    @Override
    public String toString(){
        return getData();
    }
    @Override
    public HJ212Data clone(){
        return new Parser(getData());
    };
    public static final class Builder {
        final HJ212Data data;
        private String hj212;
        public Builder(){
            this.data = new HJ212Data(){
                @Override
                public String getData() {
                    return hj212;
                }
            };
        }
        public Builder(HJ212Data data){
            this.data = data.clone();
        }
        public Builder QN(String QN){
            data.QN = QN;
            return this;
        }
        public Builder ST(String ST){
            data.ST = ST;
            return this;
        }
        public Builder CN(String CN){
            data.CN = CN;
            return this;
        }
        public Builder PW(String PW){
            data.PW  = PW;
            return this;
        }
        public Builder MN(String MN){
            data.MN  = MN;
            return this;
        }
        public Builder version(int version){
            data.version  = version;
            return this;
        }
        public Builder D(int D){
            data.D = D;
            return this;
        }
        public Builder A(int A){
            data.A = A;
            return this;
        }

        public Builder PNUM(Integer PNUM){
            data.PNUM = PNUM;
            return this;
        }

        public Builder PNO(Integer PNO){
            data.PNO = PNO;
            return this;
        }
        public Builder Cps(CPS cps){
            data.cps = cps;
            return this;
        }
        public Builder clearCP(){
            data.PNUM = null ;
            data.PNO = null;
            data.cps=CPS.create("");
            return this;
        }
        public HJ212Data build(){
            //V5 V4 V3 V2 V1 V0 D A  ,000001 表示本次标准修订版本号
            int flag = data.getVersion()<<2;
            flag |=((data.getD()& 0x1)<<1);
            flag |=(data.getA()& 0x1);
            ImmutableMap.Builder<Object, Object> put = ImmutableMap.builder()
                    .put("QN", data.getQN())
                    .put("ST", data.getST())
                    .put("CN", data.getCN())
                    .put("PW", data.getPW())
                    .put("MN", data.getMN())
                    .put("Flag", flag);
            if(null!=data.getPNUM()){
                put.put("PNUM", data.getPNUM());
            }
            if(null!=data.getPNO()){
                put.put("PNO", data.getPNO());
            }
            String join = Joiner.on(";")
                    .withKeyValueSeparator("=")
                    .join(put.build());
            hj212 =  join+";"+("CP=&&" + data.getCps() + "&&");
            return new HJ212Data.Parser(hj212);
        }
    }

    public final static class Parser extends HJ212Data{
        private final String data;
        public Parser(String data){
            this.data =data;
            parseData(data);
        }
        public String getData() {
            return data;
        }
        private void parseData(String data){
            int d1 = data.indexOf(";CP=&&");
            String items = data.substring(0, d1);
            Iterable<String> split = Splitter.on(';').split(items);
            for(String item:split){
                int i = item.indexOf('=');
                String key = item.substring(0,i);
                String value = item.substring(i+1);
                if("QN".equals(key)){
                /*
                请求编码 QN
                 */
                    super.QN = value ;
                }else if("ST".equals(key)){
                    // 系统编码 5字符		ST=21
                    super.ST = value;
                }else if("CN".equals(key)){
                    // 命令编码 7字符		CN=2011
                    super.CN = value;
                }else if("PW".equals(key)){
                    super.PW = value;
                }else if("MN".equals(key)){
                    // 设备标识 27字符	MN=[0-9A-F]
                    super.MN = value;
                }else if("PNUM".equals(key)){
                    //总包数
                    super.PNUM = Integer.valueOf(value);
                }else if("PNO".equals(key)){
                    //包号
                    super.PNO = Integer.valueOf(value);
                }else if("Flag".equals(key)){
                /*
                Flag=标志位，这个标志位包含标准版本号、是否拆分包、数据是否应答。
V5 V4 V3 V2 V1 V0 D A
V5~V0：标准版本号；Bit：000000 表示标准 HJ/T 212-2005，000001 表
示本次标准修订版本号。
A：命令是否应答；Bit：1-应答，0-不应答。
D：是否有数据包序号；Bit：1-数据包中包含包号和总包数两部分,0-
数据包中不包含包号和总包数两部分。
示例：Flag=7 表示标准版本为本次修订版本号，数据段需要拆分并且命
令需要应答
                 */
                    int flag = Integer.valueOf(value);
                    int version = flag>>2;
                    int D = (flag & 0x2)>>1;
                    int A = flag & 0x1;
                    super.version = version;;
                    super.D =D;
                    super.A =A;
                }
            }
            String cps = data.substring(d1);
            int start = cps.indexOf("&&");
            int end = cps.indexOf("&&",start+2);
            setCps(CPS.create(cps.substring(start + 2, end)));
        }

    }
}